home *** CD-ROM | disk | FTP | other *** search
Text File | 1998-01-27 | 15.7 KB | 598 lines | [TEXT/CWIE] |
- /*
- File: SampleCMPlugin.cp
-
- Contains: Sample Contextual Menu plugin
-
- Written by: Arno Gourdol
-
- Copyright: 1997, Apple Computer, Inc. All rights reserved.
-
- */
-
-
- // Class Header
- #include "SampleCMPlugin.h"
-
-
- // Mac OS Includes
- #include <AERegistry.h>
- #include <CodeFragments.h>
- #include <ContextualMenuPlugins.h>
- #include <Files.h>
- #include <Gestalt.h>
- #include <TextEdit.h>
- #include <Resources.h>
- #include "Appearance.h"
- #include <TextUtils.h>
-
-
- // SOM Includes
- #include <som.xh>
-
-
- // Stuffit headers
- #include "StuffItEngineLib.h"
- #include "StuffItEngineLib_LL.h"
-
-
- // Metrowerks init functions
- extern pascal OSErr __initialize(CFragInitBlockPtr);
-
-
- // Strings
- enum
- {
- // STR# containing command strings
- kCommandStrings = 129, // STR# id
- kExpandCommandString = 1,
- kCompressCommandString = 2,
-
- // STR# containing text for alerts
- kAlertStrings = 128, // STR# id
- kAlertPrimaryTextSingular = 1,
- kAlertPrimaryTextPlural = 2,
- kAlertSecondaryText = 3,
- kAlertDefaultButton = 4,
- kAlertCancelButton = 5
- };
-
-
- // Command IDs
- // Those numbers are arbitrary integers
- enum
- {
- kExpandCommand = 100,
- kCompressCommand = 101
- };
-
-
- // Function declarations
- pascal OSErr SampleCMPluginInitialize(CFragInitBlockPtr init);
- OSStatus AddCommandToAEDescList( ConstStr255Param inCommandString,
- SInt32 inCommandID,
- AEDescList* ioCommandList);
- void ExpandFile(FSSpec* file,
- Boolean deleteArchive);
- UInt32 GetFileListStatus( AEDescList* fileList,
- Boolean& areExpandable,
- Boolean& areCompressable);
- void CompressFiles( FSSpecArrayHandle fileList);
-
-
-
-
- // ---------------------------------------------------------------------------
- // SampleCMPluginInitialize
- // ---------------------------------------------------------------------------
- // Contextual Menu Plugins must register
- // themselves in their init routine.
-
- pascal OSErr
- SampleCMPluginInitialize(CFragInitBlockPtr init)
- {
- // Initialize Metrowerks libraries
- OSErr err = __initialize(init);
-
- // Register our class with SOM
- if (err == noErr)
- somNewClass(SampleCMPlugin);
-
- return err;
- }
-
-
-
- // ---------------------------------------------------------------------------
- // SampleCMPlugin::Initialize
- // ---------------------------------------------------------------------------
- // Initialize is called once per class instance
-
- OSStatus
- SampleCMPlugin::Initialize( Environment*,
- FSSpec* inFileSpec)
- {
- // Remember our resource file
- BlockMoveData(inFileSpec, &fPluginFile, sizeof(FSSpec));
-
- return noErr;
- }
-
-
-
- // ---------------------------------------------------------------------------
- // SampleCMPlugin::ExamineContext
- // ---------------------------------------------------------------------------
- // Have a look at the selection and decides whether to display any commands
-
- OSStatus
- SampleCMPlugin::ExamineContext( Environment*,
- AEDesc *inContextDescriptor,
- SInt32 inTimeOutInTicks,
- AEDescList* ioCommands,
- Boolean* outNeedMoreTime)
- {
- #pragma unused(inTimeOutInTicks)
-
- OSStatus err = noErr;
-
- // Open our resource file (the StuffIt engine needs this)
- SInt16 refNum = FSpOpenResFile(&fPluginFile, fsCurPerm);
-
- // Check the right version of the Stuffit engine is available
- {
- SInt32 magicCookie = 0;
-
- err = OpenSITEngine(kUseExternalEngine, &magicCookie);
-
- if (err == noErr
- &&
- GetSITEngineVersion(magicCookie) < kCurrentLibraryVersion
- )
- {
- // Return an error if the wrong version was found
- err = paramErr;
- }
-
- if (magicCookie != 0)
- CloseSITEngine(magicCookie);
- }
-
- // Make sure the descriptor isn't null
- if (err == noErr && inContextDescriptor != NULL)
- {
- Boolean areExpandable;
- Boolean areCompressable;
-
- fSelectionCount = GetFileListStatus( inContextDescriptor,
- areExpandable,
- areCompressable);
-
- if (areExpandable)
- {
- // Add the expand command to the command list
- Str255 commandString;
- GetIndString(commandString, kCommandStrings, kExpandCommandString);
- err = ::AddCommandToAEDescList(commandString, kExpandCommand, ioCommands);
- }
-
- if (areCompressable)
- {
- // Add the compress command to the command list
- Str255 commandString;
- GetIndString(commandString, kCommandStrings, kCompressCommandString);
- err = ::AddCommandToAEDescList(commandString, kCompressCommand, ioCommands);
- }
- }
-
- // Close our resource file now
- CloseResFile(refNum);
-
- // We're done so we don't need more time
- *outNeedMoreTime = false;
-
- return err;
- }
-
-
-
- // ---------------------------------------------------------------------------
- // SampleCMPlugin::HandleSelection
- // ---------------------------------------------------------------------------
- // Carry out the command that the user selected. The commandID indicates
- // which command was selected
-
- OSStatus
- SampleCMPlugin::HandleSelection( Environment* ev,
- AEDesc *inContextDescriptor,
- SInt32 inCommandID)
- {
- // Open our resource file (the StuffIt engine needs this)
- SInt16 refNum = FSpOpenResFile(&fPluginFile, fsCurPerm);
-
- ProcessFileList(ev, inContextDescriptor, inCommandID);
-
- CloseResFile(refNum);
-
- return noErr;
- }
-
-
-
- // ---------------------------------------------------------------------------
- // SampleCMPlugin::PostMenuCleanup
- // ---------------------------------------------------------------------------
-
- OSStatus
- SampleCMPlugin::PostMenuCleanup(Environment*)
- {
- // Nothing special to do in the cleanup
- return noErr;
- }
-
-
-
- // ---------------------------------------------------------------------------
- // AddCommandToAEDescList
- // ---------------------------------------------------------------------------
-
- OSStatus
- AddCommandToAEDescList( ConstStr255Param inCommandString,
- SInt32 inCommandID,
- AEDescList* ioCommandList)
- {
- OSStatus theError = noErr;
-
- AERecord theCommandRecord = {typeNull, NULL};
-
- do
- {
- // create an apple event record for our command
- theError = ::AECreateList(NULL, 0, true, &theCommandRecord);
- if (theError != noErr) break;
-
- // stick the command text into the aerecord
- theError = ::AEPutKeyPtr(&theCommandRecord, keyAEName, typeChar,
- &inCommandString[1], inCommandString[0]);
- if (theError != noErr) break;
-
- // stick the command ID into the AERecord
- theError = ::AEPutKeyPtr(&theCommandRecord, keyContextualMenuCommandID, typeLongInteger,
- &inCommandID, sizeof (inCommandID));
- if (theError != noErr) break;
-
- // stick this record into the list of commands that we are passing back to CMM
- theError = ::AEPutDesc(ioCommandList, // the list we're putting our command into
- 0, // stick this command onto the end of our list
- &theCommandRecord); // the command I'm putting into the list
-
- } while (false);
-
- // clean up after ourself; dispose of the AERecord
- AEDisposeDesc(&theCommandRecord);
-
- return theError;
- }
-
-
-
- // ---------------------------------------------------------------------------
- // GetFileListStatus
- // ---------------------------------------------------------------------------
- // Return if all the files are expandable or compressable.
- // Return the number of files in the selection
-
- UInt32
- GetFileListStatus( AEDescList* fileList,
- Boolean& areExpandable,
- Boolean& areCompressable)
- {
- OSErr err;
- UInt16 expandableCount = 0;
- UInt16 compressableCount = 0;
-
- SInt32 listItemsCount = 0;
- if (AECountItems(fileList, &listItemsCount) == noErr)
- {
- for (int i = 1; i <= listItemsCount; i++)
- {
- // Get ith item in the file list
- AEDesc file = {typeNull, NULL};
- AEKeyword theKeyword;
- err = ::AEGetNthDesc(fileList, i, typeWildCard, &theKeyword, &file);
- if (err != noErr) break;
-
- // Try to get an FSSpec out of the item in the descriptor; make sure to
- // coerce it, cuz the app may have passed an object specifier.
- AEDesc coercedFile = {typeNull, NULL};
- err = ::AECoerceDesc(&file, typeFSS, &coercedFile);
- if (err != noErr) break;
-
- // Pull the FSSpec out of the descriptor
- FSSpec fileSpec;
- ::BlockMoveData(*coercedFile.dataHandle, &fileSpec,
- ::GetHandleSize(coercedFile.dataHandle));
-
- // Disposed of the AEDesc
- AEDisposeDesc(&file);
- AEDisposeDesc(&coercedFile);
-
- // Get info about the file
- CInfoPBRec fileInfo;
- fileInfo.hFileInfo.ioCompletion = NULL; // synchronous
- fileInfo.hFileInfo.ioNamePtr = fileSpec.name;
- fileInfo.hFileInfo.ioVRefNum = fileSpec.vRefNum;
- fileInfo.hFileInfo.ioFDirIndex = 0; // search for the named item
- fileInfo.hFileInfo.ioDirID = fileSpec.parID;
- err = ::PBGetCatInfoSync(&fileInfo);
- if (err != noErr) break;
-
- // see if we have a file and not a folder
- if ((fileInfo.hFileInfo.ioFlAttrib & ioDirMask) == 0)
- {
- // Check the file's suffix
- OSType suffix = 0;
- OSType fileType = fileInfo.hFileInfo.ioFlFndrInfo.fdType;
- if (*fileInfo.hFileInfo.ioNamePtr > 3)
- {
- suffix = *(OSType*)&fileInfo.hFileInfo.ioNamePtr[*fileInfo.hFileInfo.ioNamePtr - 3];
- };
-
- if (suffix == '.sit' || suffix == '.bin' || suffix == '.hqx' ||
- fileType == 'SIT!')
- expandableCount++;
- else
- compressableCount++;
- }
- else
- {
- compressableCount++;
- }
- }
- }
-
- if (listItemsCount != 0)
- {
- areExpandable = expandableCount == listItemsCount;
- areCompressable = compressableCount == listItemsCount;
- }
-
- return expandableCount + compressableCount;
- }
-
-
-
- // ---------------------------------------------------------------------------
- // ProcessFileList
- // ---------------------------------------------------------------------------
- // Process a list of files
-
- void
- SampleCMPlugin::ProcessFileList( Environment*,
- AEDescList* fileList,
- SInt32 commandID)
- {
- OSErr err;
- FSSpecArrayHandle fsSpecHandle;
- Boolean optionKeyDown = false;
- Boolean deleteArchives = false;
-
- {
- EventRecord event;
- OSEventAvail(-1, &event);
- optionKeyDown = (event.modifiers & optionKey) != 0;
- }
-
-
- if (commandID == kExpandCommand && optionKeyDown)
- {
- SInt32 result;
-
- err = Gestalt(gestaltAppearanceExists, &result);
- if (err == noErr && (result & (1 << gestaltAppearanceExists)))
- {
- SInt16 itemHit;
- Str255 defaultButton;
- Str255 cancelButton;
-
- GetIndString(defaultButton, kAlertStrings, kAlertDefaultButton);
- GetIndString(cancelButton, kAlertStrings, kAlertCancelButton);
-
- AlertStdAlertParamRec stdAlertParam;
- stdAlertParam.movable = false;
- stdAlertParam.helpButton = false;
- stdAlertParam.filterProc = nil;
- stdAlertParam.defaultText = defaultButton;
- stdAlertParam.cancelText = cancelButton;
- stdAlertParam.otherText = nil;
- stdAlertParam.defaultButton = 1;
- stdAlertParam.cancelButton = 2;
- stdAlertParam.position = kWindowDefaultPosition;
-
- {
- Str255 primaryAlertText;
- Str255 secondaryAlertText;
-
- if (fSelectionCount > 1)
- GetIndString(primaryAlertText, kAlertStrings, kAlertPrimaryTextPlural);
- else
- GetIndString(primaryAlertText, kAlertStrings, kAlertPrimaryTextSingular);
- GetIndString(secondaryAlertText, kAlertStrings, kAlertSecondaryText);
- StandardAlert( kAlertCautionAlert,
- primaryAlertText,
- secondaryAlertText,
- &stdAlertParam,
- &itemHit);
- }
- if (itemHit == 1)
- deleteArchives = true;
- }
- }
-
- if (commandID == kCompressCommand)
- {
- fsSpecHandle = NewFSSpecList();
- }
-
-
- SInt32 listItemsCount = 0;
- if (AECountItems(fileList, &listItemsCount) == noErr)
- {
- for (int i = 1; i <= listItemsCount; i++)
- {
- // Get ith item in the file list
- AEDesc file = {typeNull, NULL};
- AEKeyword theKeyword;
- err = ::AEGetNthDesc(fileList, i, typeWildCard, &theKeyword, &file);
- if (err != noErr) break;
-
- // Try to get an FSSpec out of the item in the descriptor; make sure to
- // coerce it, cuz the app may have passed an object specifier.
- AEDesc coercedFile = {typeNull, NULL};
- err = ::AECoerceDesc(&file, typeFSS, &coercedFile);
- if (err != noErr) break;
-
- // Pull the FSSpec out of the descriptor
- FSSpec fileSpec;
- ::BlockMoveData(*coercedFile.dataHandle, &fileSpec,
- ::GetHandleSize(coercedFile.dataHandle));
-
- // Disposed of the AEDesc
- AEDisposeDesc(&file);
- AEDisposeDesc(&coercedFile);
-
- if (commandID == kExpandCommand)
- {
- ExpandFile(&fileSpec, deleteArchives);
- }
- else
- {
- err = AddToFSSpecList(&fileSpec, fsSpecHandle);
- }
- }
- }
-
- if (commandID == kCompressCommand)
- {
- CompressFiles(fsSpecHandle);
- DisposeFSSpecList(fsSpecHandle);
- }
-
- }
-
-
-
- // ---------------------------------------------------------------------------
- // ExpandFile
- // ---------------------------------------------------------------------------
- // Expand a file
-
- void
- ExpandFile(FSSpec* file, Boolean deleteArchive)
- {
- long magicCookie = 0;
- OSErr err;
- FSSpec result;
-
- // check to make sure StuffItEngine exists and is the right version
- err = OpenSITEngine(kUseExternalEngine, &magicCookie);
-
- if (err == noErr)
- {
- // We have the engine, let's expand!
- short targetType;
-
- // Go throught the engine as many times as it takes to get to a file that
- // is not recognized. Most common reason this is necessary is .sit.hqx
- do
- {
- // First, figure out what type of file we have
- targetType = DetermineFileType(file);
-
- if (targetType == ftype_StuffIt)
- {
- // The file is a stuffit archive, so unstuff it
- short conflictAction;
-
- //if (replaceExistingFile)
- // conflictAction = USIT_conflict_replaceExisting;
- //else
- conflictAction = USIT_conflict_autoRename;
-
- err = UnStuffFSSpec_Enhanced(magicCookie, file,
- nil, // unstuff into the same folder
- &result, // we want the resulting file spec
- kDontPromptForDestination, // don't prompt the user
- deleteArchive, // delete the archive when done
- createFolder_Smart, // create a new folder if it makes sense
- kSaveComments, // save any archive comments
- kStopOnAbort, // if the user says abort, do it
- conflictAction, // conflict action as set above
- nil, // no password
- true, // display progress only if requested by client
- kNoCallback, // no alert callback
- kNoCallback, // no status callback
- kNoCallback); // no periodic callback
-
-
- }
- else if (targetType != ftype_unknown)
- {
- // The file is some other type that stuffit understands, so expand it
- err = ExpandFSSpec(magicCookie, targetType, file,
- nil, // expand file into same folder
- &result, // we want the resulting file spec
- createFolder_Smart, // create a new folder if it makes sense
- kDeleteOriginal, // delete the original file
- textConvert_Never); // we have already converted the EOLs
-
- }
-
- // If the engine does not know about this file type, we assume
- // no expansion is necessary
-
- // If there was no error, copy the resultant file name into our file spec
- // to be eventually passed back to the client
- if (err == noErr)
- BlockMoveData(result.name, file->name, result.name[0]+1);
- } while (targetType != ftype_unknown);
-
- }
-
- if (magicCookie != 0)
- CloseSITEngine(magicCookie);
-
- }
-
-
-
- // ---------------------------------------------------------------------------
- // CompressFiles
- // ---------------------------------------------------------------------------
- // Compress files
-
- void
- CompressFiles(FSSpecArrayHandle fileList)
- {
- long magicCookie = 0;
- OSErr err;
-
- // check to make sure StuffItEngine exists and is the right version
- err = OpenSITEngine(kUseExternalEngine, &magicCookie);
-
- if (err == noErr)
- {
- // We have the engine, let's compress!
- FSSpec fileSpec;
- err = StuffFSSList(magicCookie, fileList,
- nil, &fileSpec,
- true, false, false,
- true, true,
- USIT_conflict_autoRename);
-
- }
-
- if (magicCookie != 0)
- CloseSITEngine(magicCookie);
-
- }
-